package com.jack006.user.service.impl;

import com.github.pagehelper.PageHelper;
import com.jack006.api.service.BaseService;
import com.jack006.enums.Sex;
import com.jack006.pojo.AppUser;
import com.jack006.pojo.Fans;
import com.jack006.pojo.eo.FansEO;
import com.jack006.pojo.vo.FansCountsVO;
import com.jack006.pojo.vo.RegionRatioVO;
import com.jack006.user.mapper.FansMapper;
import com.jack006.user.service.MyFansService;
import com.jack006.user.service.UserService;
import com.jack006.utils.PagedGridResult;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.n3r.idworker.Sid;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.ResultsExtractor;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Classname MyFansServiceImpl
 * @Description 粉丝管理实现类
 * @Date 2021-07-14 08:42
 * @Created by jack
 */
@Service
public class MyFansServiceImpl extends BaseService implements MyFansService {

    public static final String[] regions = {"北京", "天津", "上海", "重庆",
            "河北", "山西", "辽宁", "吉林", "黑龙江", "江苏", "浙江", "安徽", "福建", "江西", "山东",
            "河南", "湖北", "湖南", "广东", "海南", "四川", "贵州", "云南", "陕西", "甘肃", "青海", "台湾",
            "内蒙古", "广西", "西藏", "宁夏", "新疆",
            "香港", "澳门"};

    @Autowired
    private FansMapper fansMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private Sid sid;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public boolean isMeFollowThisWriter(String writerId, String fanId) {

        Fans fans = new Fans();
        fans.setFanId(fanId);
        fans.setWriterId(writerId);

        int count = fansMapper.selectCount(fans);

        return count > 0 ? true : false;
    }

    @Transactional
    @Override
    public void follow(String writerId, String fanId) {
        AppUser fanInfo = userService.getUserById(fanId);
        String fanPkId = sid.nextShort();
        Fans fans = new Fans();
        fans.setId(fanPkId);
        fans.setFanId(fanId);
        fans.setWriterId(writerId);
        fans.setFace(fanInfo.getFace());
        fans.setFanNickname(fanInfo.getNickname());
        fans.setSex(fanInfo.getSex());
        fans.setProvince(fanInfo.getProvince());
        fansMapper.insert(fans);
        // redis 作家粉丝数累加
        redisOperator.increment(REDIS_WRITER_FANS_COUNTS+":"+writerId,1);
        // redis 当前用户（我的）关注数累加
        redisOperator.increment(REDIS_MY_FOLLOW_COUNTS+":"+fanId,1);


        // 保存到粉丝关系到 es 中
        FansEO fansEO = new FansEO();
        BeanUtils.copyProperties(fans, fansEO);
        IndexQuery iq = new IndexQueryBuilder().withObject(fansEO).build();
        elasticsearchTemplate.index(iq);
    }

    @Transactional
    @Override
    public void unFollow(String writerId, String fanId) {

        Fans fans = new Fans();
        fans.setFanId(fanId);
        fans.setWriterId(writerId);
        fansMapper.delete(fans);

        // redis 作家粉丝数累减
        redisOperator.decrement(REDIS_WRITER_FANS_COUNTS+":"+writerId,1);
        // redis 当前用户（我的）关注数累减
        redisOperator.decrement(REDIS_MY_FOLLOW_COUNTS+":"+fanId,1);

        // 删除 es 中的粉丝关系，DeleteQuery： 根据条件删除
        DeleteQuery dq = new DeleteQuery();
        dq.setQuery(QueryBuilders.termQuery("writerId",writerId));
        dq.setQuery(QueryBuilders.termQuery("fanId",fanId));
        elasticsearchTemplate.delete(dq,FansEO.class);
    }

    @Override
    public PagedGridResult queryMyFansList(String writerId, Integer page, Integer pageSize) {

        Fans fans = new Fans();
        fans.setWriterId(writerId);

        PageHelper.startPage(page,pageSize);
        List<Fans> list = fansMapper.select(fans);
        return setterPagedGrid(list,page);
    }

    @Override
    public Integer queryFansCounts(String writerId, Sex sex) {

        Fans fans = new Fans();
        fans.setWriterId(writerId);
        fans.setSex(sex.type);

        Integer count = fansMapper.selectCount(fans);
        return count;
    }

    @Override
    public List<RegionRatioVO> queryRegionRatioCounts(String writerId) {

        Fans fans = new Fans();
        fans.setWriterId(writerId);

        List<RegionRatioVO> regionRatioVOList = new ArrayList<>();
        for (String region : regions) {
            fans.setProvince(region);
            int count = fansMapper.selectCount(fans);

            RegionRatioVO regionRatioVO = new RegionRatioVO();
            regionRatioVO.setName(region);
            regionRatioVO.setValue(count);

            regionRatioVOList.add(regionRatioVO);
        }
        return regionRatioVOList;
    }

    @Override
    public void forceUpdateFanInfo(String relationId, String fanId) {
        // 1、查询用户信息
        AppUser user = userService.getUserById(fanId);


        // 2、更新用户信息到 db 和 Des 中

        Fans fans = new Fans();
        fans.setFace(user.getFace());
        fans.setFanNickname(user.getNickname());
        fans.setSex(user.getSex());
        fans.setProvince(user.getProvince());

        fansMapper.updateByPrimaryKeySelective(fans);

        // 3、更新到 es中
        Map<String,Object> updateMap = new HashMap<>();
        updateMap.put("face",user.getFace());
        updateMap.put("fanNicename",user.getNickname());
        updateMap.put("sex",user.getSex());
        updateMap.put("province",user.getProvince());

        IndexRequest ir = new IndexRequest();
        ir.source(updateMap);


        UpdateQuery uq = new UpdateQueryBuilder()
                .withClass(FansEO.class)
                .withId(relationId)
                .withIndexRequest(ir)
                .build();

        elasticsearchTemplate.update(uq);

    }

    @Override
    public FansCountsVO queryFansESCounts(String writerId) {

        TermsAggregationBuilder aggregationBuilder = AggregationBuilders
                .terms("sex_counts")
                .field("sex");

        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery("writerId",writerId))
                .addAggregation(aggregationBuilder)
                .build();

        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, new ResultsExtractor<Aggregations>() {

            @Override
            public Aggregations extract(SearchResponse searchResponse) {
                return searchResponse.getAggregations();
            }
        });

        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        LongTerms longTerms = (LongTerms)aggregationMap.get("sex_counts");
        List<LongTerms.Bucket> bucketList = longTerms.getBuckets();

        FansCountsVO fansCountsVO = new FansCountsVO();
        for (int i = 0; i < bucketList.size(); i++) {
            LongTerms.Bucket bucket = bucketList.get(i);
            Long docCount = bucket.getDocCount();
            Long key = (Long)bucket.getKey();

            if (key.intValue() == Sex.woman.type) {
                fansCountsVO.setWomanCounts(docCount.intValue());
            }else if(key.intValue() == Sex.man.type) {
                fansCountsVO.setManCounts(docCount.intValue());
            }
        }

        if (bucketList.isEmpty()) {
            fansCountsVO.setManCounts(0);
            fansCountsVO.setWomanCounts(0);
        }

        return fansCountsVO;
    }

    @Override
    public List<RegionRatioVO> queryRegionRatioESCounts(String writerId) {

        TermsAggregationBuilder aggregationBuilder = AggregationBuilders
                .terms("region_counts")
                .field("province");

        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery("writerId", writerId))
                .addAggregation(aggregationBuilder)
                .build();

        Aggregations aggs = elasticsearchTemplate.query(searchQuery, new ResultsExtractor<Aggregations>() {
            @Override
            public Aggregations extract(SearchResponse response) {
                return response.getAggregations();
            }
        });

        Map aggMap = aggs.asMap();
        StringTerms strTerms = (StringTerms) aggMap.get("region_counts");
        List bucketList = strTerms.getBuckets();

        List<RegionRatioVO> list = new ArrayList<>();
        for (int i = 0 ; i < bucketList.size() ; i ++) {
            StringTerms.Bucket bucket = (StringTerms.Bucket)bucketList.get(i);
            Long docCount = bucket.getDocCount();
            String key = (String)bucket.getKey();

            System.out.println(key);
            System.out.println(docCount);

            RegionRatioVO regionRatioVO = new RegionRatioVO();
            regionRatioVO.setName(key);
            regionRatioVO.setValue(docCount.intValue());
            list.add(regionRatioVO);
        }

        return list;
    }
}
